let { ccclass: cclass, property: prop, executeInEditMode } = cc._decorator;
let assets = [];

if (CC_EDITOR) {
    window["Editor"].assetdb.queryAssets('db://assets/**\/*', 'prefab', function (err, results) {
        assets = results;
    });

    cc._decorator.property = function (ctorProtoOrOptions) {
        if (ctorProtoOrOptions) {
            let func = prop(...arguments);
            return function (target, propertyKey) {
                func(...arguments);
                if (target.constructor._members) {
                    let type = ctorProtoOrOptions.type || ctorProtoOrOptions;
                    if (cc.js.isChildClassOf(type, cc.Node) || cc.js.isChildClassOf(type, cc.Component)) {
                        target.constructor._members[propertyKey] = type;
                    } else if (cc.js.isChildClassOf(type, cc.Prefab)) {
                        target.constructor._assets.push({ name: propertyKey, type })
                    }
                }
            }
        }
    }
}

/**自动绑定的组件 */
@cclass
//@executeInEditMode
class AutoBindComponent extends cc.Component {
    private static _members = {};
    private static _assets = [];
    private _isReference: Map<string, boolean> = new Map();

    /**绑定节点或组件 */
    private bindProperty(node: cc.Node) {
        let type = AutoBindComponent._members[node.name];
        if (type) {
            if (this._isReference.get(node.name)) {
                cc.warn("有同名属性被引用!", node.name);
            } else {
                this._isReference.set(node.name, true);
                //节点类型
                if (cc.js.isChildClassOf(type, cc.Node)) {
                    this[node.name] = node;
                } else {
                    //组件类型
                    this[node.name] = node.getComponent(type);
                }
            }
        }
        node.children.forEach(childNode => this.bindProperty(childNode));
    }

    /**绑定资源 */
    private bindAssets() {
        AutoBindComponent._assets.forEach((asset) => {
            let obj = assets.find((item) => {
                return item.url.endsWith(`${asset.name}.prefab`)
            });
            if (obj) {
                cc.loader.load({ type: 'uuid', uuid: obj.uuid }, (err, prefab) => {
                    this[asset.name] = prefab;
                });
            }
        });
    }

    /**响应编辑器Reset按钮 */
    resetInEditor() {
        this._isReference.clear();
        this.bindProperty(this.node);
        this.bindAssets();
    }
}

if (CC_EDITOR) {
    AutoBindComponent.prototype["__preload"] = function () {
        this.bindProperty(this.node);
        this.bindAssets();
    }
}

window["AutoBindComponent"] = AutoBindComponent;